home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turnbull China Bikeride
/
Turnbull China Bikeride - Disc 2.iso
/
BARNET
/
FREENET
/
HOUGHTON
/
POPST124
/
!POPstar
/
c
/
pop
< prev
next >
Wrap
Text File
|
1998-05-16
|
15KB
|
576 lines
/*
$Header: ADFS::Nisu.\044.Internet.!POPstar.RCS.pop,v.c 1.13 1998/05/16 16:33:11 root Exp root $
$Log: pop,v.c $
Revision 1.13 1998/05/16 16:33:11 root
Various changes in a futile attempt to beat the memory leak
Revision 1.12 1998/05/02 19:17:01 root
Now accepts responses of +OK with no trailing message
Revision 1.11 1998/05/02 13:59:07 root
New option for length of line terminators
Revision 1.10 1998/04/23 23:24:45 root
Another try at message sizes (overshot before :-()
Revision 1.9 1998/04/23 22:28:11 root
Another stab at getting reported message sizes to tally with LIST!
Revision 1.8 1998/04/19 16:03:49 root
Reports socket errors in textual form
Revision 1.7 1998/04/18 20:42:10 root
Should get reported size of messages closer to LISTed size
Revision 1.6 1998/04/16 15:07:30 root
Issues one LIST command for all messages at once
Revision 1.5 1998/03/23 19:59:53 root
. escape sequence handling corrected
Revision 1.4 1998/03/06 22:27:59 root
Corrected previous fix to QUIT when empty, was being reissued after closing socket
Revision 1.1 1998/02/25 21:57:19 root
Initial revision
Revision 1.1 1998/02/25 21:57:19 root
Initial revision
*/
#include <stdio.h>
#include <stdlib.h>
#include "memleak.h"
#include <string.h>
#include <time.h>
#include "swis.h"
#include "sys/errno.h"
#include "event.h"
#include "quit.h"
#include "bufsock.h"
#include "config.h"
#include "err.h"
#include "errlist.h"
#include "ftrunc.h"
#include "log.h"
#include "msgs.h"
#include "pop.h"
#include "stopquit.h"
#include "treport.h"
#include "user.h"
#include "xconnect.h"
#include "xsock.h"
typedef struct {
bufsock bs;
const user_info *u;
bool negotiated;
int stat_count;
int stat_size;
FILE *fp;
long last_offset;
int msg;
int msg_cur;
status_handle status;
stopquit_t stopped;
int *list;
} pop_info;
static xsock pop_socket = -1;
static bool pop_exit_installed = false;
static void pop_close()
{
if (pop_socket != -1)
{
xsock_close(pop_socket);
pop_socket = -1;
}
}
static bool pop_exe_command(pop_info *info, const char *command,
bool (*handler)(xsock, pop_info *, const char *))
{
if (!xsock_xwrite(pop_socket, command))
return false;
return (*handler)(pop_socket, info, command);
}
static bool pop_handle_user(xsock sock, pop_info *info, const char *com)
{
const char *pop_buf;
bool wasline;
sock=sock; com=com;
xsyslog_logmessage(log_NAME, msgs_lookup1("Awaiting", com), log_DebugInfo);
if ((pop_buf = bufsock_read_line(info->bs, &wasline)) == 0)
{
xsyslogf(log_NAME, log_SocketError,
msgs_lookup2("NoRep", "USER", errlist_str(errno)), errno);
return false;
}
if (strncmp(pop_buf, "+OK", 3))
{
xsyslog_logmessage(log_NAME, msgs_lookup1("BadRep", "USER"),
log_ServerError);
xsyslog_logmessage(log_NAME, pop_buf, log_ServerError);
return false;
}
xsyslog_logmessage(log_NAME, pop_buf, log_ServerResponse);
/*while (!wasline && bufsock_read_line(info->bs, &wasline));*/
return true;
}
static bool pop_handle_pass(xsock sock, pop_info *info, const char *com)
{
const char *pop_buf;
bool wasline;
sock=sock; com=com;
xsyslog_logmessage(log_NAME, msgs_lookup1("Awaiting", com), log_DebugInfo);
if ((pop_buf = bufsock_read_line(info->bs, &wasline)) == 0)
{
xsyslogf(log_NAME, log_SocketError,
msgs_lookup2("NoRep", "PASS", errlist_str(errno)), errno);
return false;
}
if (strncmp(pop_buf, "+OK", 3))
{
xsyslog_logmessage(log_NAME, msgs_lookup1("BadRep", "PASS"),
log_ServerError);
xsyslog_logmessage(log_NAME, pop_buf, log_ServerError);
return false;
}
xsyslog_logmessage(log_NAME, pop_buf, log_ServerResponse);
/*while (!wasline && bufsock_read_line(info->bs, &wasline));*/
return true;
}
static bool pop_handle_stat(xsock sock, pop_info *info, const char *com)
{
const char *pop_buf;
bool wasline;
sock=sock; com=com;
xsyslog_logmessage(log_NAME, msgs_lookup1("Awaiting", com), log_DebugInfo);
if ((pop_buf = bufsock_read_line(info->bs, &wasline)) == 0)
{
xsyslogf(log_NAME, log_SocketError,
msgs_lookup2("NoRep", "STAT", errlist_str(errno)), errno);
return false;
}
if (strncmp(pop_buf, "+OK", 3))
{
xsyslog_logmessage(log_NAME, msgs_lookup1("BadRep", "STAT"),
log_ServerError);
xsyslog_logmessage(log_NAME, pop_buf, log_ServerError);
return false;
}
xsyslog_logmessage(log_NAME, pop_buf, log_ServerResponse);
sscanf(pop_buf + 4, "%d %d", &info->stat_count, &info->stat_size);
status_count_total(info->status, info->stat_count);
status_total_total(info->status, info->stat_size);
if (info->stat_count && config_lookup_bool("List:Y"))
{
int i;
info->list = malloc(info->stat_count * sizeof(int));
for (i = 0; i < info->stat_count; ++i)
info->list[i] = -1;
}
/*while (!wasline && bufsock_read_line(info->bs, &wasline));*/
return info->negotiated = true;
}
static bool pop_negotiate(pop_info *info)
{
const char *pop_buf;
bool wasline;
char cmd[32];
info->negotiated = false;
status_show_misc(info->status, msgs_lookup1("LogIn", info->u->name));
if ((pop_buf = bufsock_read_line(info->bs, &wasline)) == 0)
{
xsyslogf(log_NAME, log_SocketError,
msgs_lookup1("NoLoginRep", errlist_str(errno)), errno);
return false;
}
xsyslog_logmessage(log_NAME, pop_buf, log_ServerResponse);
if (strncmp(pop_buf, "+OK", 3))
{
xsyslog_logmessage(log_NAME, pop_buf, log_ServerError);
return false;
}
/*while (!wasline && bufsock_read_line(info->bs, &wasline));*/
sprintf(cmd, "USER %s", info->u->name);
if (!pop_exe_command(info, cmd, pop_handle_user))
return false;
sprintf(cmd, "PASS %s", info->u->password);
if (!pop_exe_command(info, cmd, pop_handle_pass))
return false;
if (!pop_exe_command(info, "STAT", pop_handle_stat))
return false;
return info->negotiated;
}
static bool pop_handle_list(xsock sock, pop_info *info, const char *com)
{
const char *pop_buf;
bool wasline;
int msg, size;
sock=sock;
xsyslog_logmessage(log_NAME, msgs_lookup1("Awaiting", com), log_DebugInfo);
if ((pop_buf = bufsock_read_line(info->bs, &wasline)) == 0)
{
xsyslogf(log_NAME, log_SocketError,
msgs_lookup2("NoRep", "LIST", errlist_str(errno)), errno);
return false;
}
if (strncmp(pop_buf, "+OK", 3))
{
xsyslog_logmessage(log_NAME, msgs_lookup1("BadRep", "LIST"),
log_ServerError);
xsyslog_logmessage(log_NAME, pop_buf, log_ServerError);
return false;
}
xsyslog_logmessage(log_NAME, pop_buf, log_ServerResponse);
/*while (!wasline && bufsock_read_line(info->bs, &wasline));*/
while ((pop_buf = bufsock_read_line(info->bs, &wasline)) != 0 &&
pop_buf[0] && pop_buf[0] != '.')
{
sscanf(pop_buf, "%d %d", &msg, &size);
if (msg > info->stat_count)
{
treport(msgs_lookup("BadList"), log_ServerError);
xsyslog_logmessage(log_NAME, pop_buf, log_ServerError);
}
else
info->list[msg - 1] = size;
}
return true;
}
static bool pop_handle_dele(xsock sock, pop_info *info, const char *com)
{
const char *pop_buf;
bool wasline;
sock=sock; com=com;
xsyslog_logmessage(log_NAME, msgs_lookup1("Awaiting", com), log_DebugInfo);
if ((pop_buf = bufsock_read_line(info->bs, &wasline)) == 0)
{
xsyslogf(log_NAME, log_SocketError,
msgs_lookup2("NoRep", "DELE", errlist_str(errno)), errno);
return false;
}
if (strncmp(pop_buf, "+OK", 3))
{
xsyslog_logmessage(log_NAME, msgs_lookup1("BadRep", "DELE"),
log_ServerError);
xsyslog_logmessage(log_NAME, pop_buf, log_ServerError);
return false;
}
xsyslog_logmessage(log_NAME, pop_buf, log_ServerResponse);
/*while (!wasline && bufsock_read_line(info->bs, &wasline));*/
return true;
}
static void pop_show_status(const pop_info *info, bool force)
{
static int lt;
int tn;
_swix(OS_ReadMonotonicTime, _OUT(0), &tn);
if (!info->msg_cur)
{
status_count(info->status, info->msg);
if (info->list && info->list[info->msg - 1] != -1)
status_bytes_total(info->status, info->list[info->msg - 1]);
lt = tn;
}
else if (tn - lt > 25 || force)
{
status_bytes(info->status, info->msg_cur);
/*
printf("\x0bMessage %4d : %10d", info->msg, info->msg_cur);
if (info->msg_total != -1)
printf("/%-10d\n", info->msg_total);
else
printf("\n");
*/
lt = tn;
}
}
static int pop_lineterm_len;
static bool pop_handle_retr(xsock sock, pop_info *info, const char *com)
{
const char *pop_buf;
bool wasline, isline;
sock=sock;
xsyslog_logmessage(log_NAME, msgs_lookup1("Awaiting", com), log_DebugInfo);
if ((pop_buf = bufsock_read_line(info->bs, &wasline)) == 0)
{
xsyslogf(log_NAME, log_SocketError,
msgs_lookup2("NoRep", "RETR", errlist_str(errno)), errno);
return false;
}
if (strncmp(pop_buf, "+OK", 3))
{
xsyslog_logmessage(log_NAME, msgs_lookup1("BadRep", "RETR"),
log_ServerError);
xsyslog_logmessage(log_NAME, pop_buf, log_ServerError);
return false;
}
xsyslog_logmessage(log_NAME, pop_buf, log_ServerResponse);
/*while (!wasline && bufsock_read_line(info->bs, &wasline));*/
/* Write separator */
if (putc(1, info->fp) == EOF || putc('\n', info->fp) == EOF)
{
treport(msgs_lookup1("InFile", info->u->lname), log_OSError);
return false;
}
++info->msg;
info->msg_cur = 0;
pop_show_status(info, true);
for (; !info->stopped; )
{
bool escdot;
if ((pop_buf = bufsock_read_line(info->bs, &isline)) == 0)
{
xsyslogf(log_NAME, log_SocketError,
msgs_lookup2("NoRep", "RETR", errlist_str(errno)), errno);
return false;
}
if (wasline && pop_buf[0] == '.')
escdot = true;
else
escdot = false;
if (escdot)
{
if (pop_buf[1] == 0 && isline)
{
pop_show_status(info, true);
break;
}
}
info->msg_cur += (strlen(pop_buf) + pop_lineterm_len - escdot);
pop_show_status(info, false);
if (fputs(escdot ? pop_buf + 1 : pop_buf, info->fp) == EOF ||
putc('\n', info->fp) == EOF)
{
treport(msgs_lookup1("InFile", info->u->lname), log_OSError);
return false;
}
wasline = isline;
}
if (info->stopped)
return false;
info->last_offset = ftell(info->fp);
fflush(info->fp);
if (!info->u->keep)
{
char cmd[32];
sprintf(cmd, "DELE %d", atoi(com + 5));
if (!pop_exe_command(info, cmd, pop_handle_dele))
{
LOG(("Failed to add DELE command (lack of memory?)\n"));
return false;
}
}
return true;
}
static bool pop_handle_quit(xsock sock, pop_info *info, const char *com)
{
const char *pop_buf;
bool wasline;
sock=sock; com=com;
xsyslog_logmessage(log_NAME, msgs_lookup1("Awaiting", com), log_DebugInfo);
if ((pop_buf = bufsock_read_line(info->bs, &wasline)) == 0)
{
xsyslogf(log_NAME, log_SocketError,
msgs_lookup2("NoRep", "QUIT", errlist_str(errno)), errno);
return false;
}
if (strncmp(pop_buf, "+OK", 3))
{
xsyslog_logmessage(log_NAME, msgs_lookup1("BadRep", "QUIT"),
log_ServerError);
xsyslog_logmessage(log_NAME, pop_buf, log_ServerError);
return false;
}
xsyslog_logmessage(log_NAME, msgs_lookup("GoodQuit"), log_MiscInfo);
xsyslog_logmessage(log_NAME, pop_buf, log_ServerResponse);
/*while (!wasline && bufsock_read_line(info->bs, &wasline));*/
return true;
}
static bool pop_download(pop_info *info)
{
int i;
bool result = false;
char pathname[100];
char cmd[32];
status_show_user(info->status, info->u->name, info->u->server);
sprintf(pathname, "<POPstar$MailDir>.spool.mail.text.%s", info->u->lname);
info->fp = fopen(pathname, "a");
if (!info->fp)
{
treport(msgs_lookup1("InFile", info->u->lname), log_OSError);
xsock_xwrite(pop_socket, "QUIT");
return false;
}
info->last_offset = ftell(info->fp);
info->msg = 0;
if (info->list)
{
if (!pop_exe_command(info, "LIST", pop_handle_list))
{
free(info->list);
info->list = 0;
}
}
for (i = 1; i <= info->stat_count; ++i)
{
sprintf(cmd, "RETR %d", i);
if (!pop_exe_command(info, cmd, pop_handle_retr))
goto pop_download_exit;
}
if (!info->stopped)
result = true;
pop_download_exit:
xsock_xwrite(pop_socket, "QUIT");
fclose(info->fp);
if (result)
pop_handle_quit(pop_socket, info, "QUIT");
else
file_truncate(pathname, info->last_offset);
return result;
}
static bool pop_stop_handler(int c, ToolboxEvent *e, IdBlock *id, void *h)
{
c=c; e=e;
E(toolbox_get_client_handle(0, id->self_id,
(void **) &((pop_info *) h)->stopped));
xsyslog_logmessage(log_NAME, msgs_lookup("Stopped"), log_MiscInfo);
return true;
}
bool pop_fetch(int user)
{
stopquit_t stopped = stopquit_Null;
bool result = false;
pop_info *info = 0;
status_handle status = status_create();
const user_info *u = user_get(user);
pop_lineterm_len = config_lookup_num("LineTermLen:2");
status_set_label(status, msgs_lookup("User"));
/*printf("Attempting connection for %s@%s\n", u->name, u->server);*/
/* Naughty naughty, assume we can't be given an invalid index */
if ((pop_socket = xconnect_pop(u->server, status)) == -1)
{
treport(msgs_lookup2("POPConnect", u->name, u->server), log_SocketError);
status_free(status);
return false;
}
if (!pop_exit_installed)
{
atexit(pop_close);
pop_exit_installed = true;
}
if ((info = malloc(sizeof(pop_info))) == 0)
{
treport(msgs_nomem()->errmess, log_OSError);
goto pop_fetch_fail2;
}
info->status = status;
info->bs = 0;
info->u = u;
info->stopped = stopquit_Null;
info->list = 0;
if (E(event_register_toolbox_handler(-1, Quit_Quit, pop_stop_handler, info)))
goto pop_fetch_fail2;
if ((info->bs = bufsock_create(pop_socket)) == 0)
goto pop_fetch_fail;
if (!pop_negotiate(info))
{
if (!info->stopped)
treport(msgs_lookup2("NegFail", u->name, u->server), log_ServerError);
xsock_xwrite(pop_socket, "QUIT");
goto pop_fetch_fail;
}
xsyslogf(log_NAME, log_MiscInfo, msgs_lookup2("Stat", u->name, u->server),
info->stat_count, info->stat_size);
if (!info->stat_count)
{
if (xsock_xwrite(pop_socket, "QUIT") > 0)
pop_handle_quit(pop_socket, info, "QUIT");
result = true;
}
else if (pop_download(info))
result = true;
pop_fetch_fail:
E(event_deregister_toolbox_handler(-1, Quit_Quit, pop_stop_handler, info));
pop_fetch_fail2:
if (info->bs)
bufsock_free(info->bs);
status_free(status);
if (info)
stopped = info->stopped;
free(info->list);
free(info);
pop_close();
if (stopped)
stopquit_act(stopped);
return result;
}